﻿using System;
using System.Collections.Generic;
using System.Text;
using Google.GData.Calendar;
using Google.GData.Client;
using Google.GData.Extensions;
using System.Xml;

using Microsoft.JScript;
using System.Net;
using System.Resources;
using System.Reflection;
using System.IO;

namespace CalendarHelper
{
	class Program
	{

		static void Main(string[] args)
		{

			if(args.Length==0)
			{
				Assembly a = Assembly.GetExecutingAssembly();
				Stream strHelp= a.GetManifestResourceStream(typeof(Program).Namespace+ ".Help.txt");
				using (StreamReader sr = new StreamReader(strHelp))
				{
					Console.Write(sr.ReadToEnd());
				}
				Environment.Exit(0);
			}

            Console.WriteLine("job:" + args[0]);

			switch (args[0])
			{
			case "cleanCalendar":
				#region cleanCalendar
				{
					Console.WriteLine("command: buildCalendar /a googleAccount /p password /t calendarTitle");
					Dictionary<string, string> argDic = Global.Global.convertArgs(args);
					CalendarService service = createCalendarService(argDic["a"], argDic["p"]);
					CalendarQuery query = new CalendarQuery();
					query.Uri = new Uri("http://www.google.com/calendar/feeds/default/allcalendars/full");

					Console.WriteLine("Query calendars");

					CalendarFeed resultFeed = service.Query(query);
					CalendarEntry targetCalendar = null;

					Console.WriteLine("Finding the calendar:" + argDic["t"]);

					#region check if there is already a calendar with the same name
					foreach (CalendarEntry entry in resultFeed.Entries)
					{
						if (entry.Title.Text == argDic["t"])
						{
							Console.WriteLine("Found " + argDic["t"]);

							targetCalendar = entry;

							#region kill all the old items

							Console.WriteLine("Killing originals");
							EventQuery eventQuery = new EventQuery();
							eventQuery.Uri = new Uri(targetCalendar.Links[0].AbsoluteUri);
							eventQuery.NumberToRetrieve = 1000;
							// Tell the service to query:
							EventFeed eventFeed = service.Query(eventQuery);

							foreach (EventEntry eventEntry in eventFeed.Entries)
							{
								Console.Write(".");
								eventEntry.Delete();
							}
							Console.WriteLine("finish");
							#endregion


							break;

						}

					}
					#endregion
				}
				#endregion
				break;
			case "buildCalendar":
				{
					#region handle build calendar case
                    Console.WriteLine("build Calendar");

					Dictionary<string, string> argDic = Global.Global.convertArgs(args);

					CalendarService service = createCalendarService(argDic["a"], argDic["p"]);

					CalendarQuery query = new CalendarQuery();
					query.Uri = new Uri("http://www.google.com/calendar/feeds/default/owncalendars/full");

					CalendarFeed resultFeed = service.Query(query);
					CalendarEntry targetCalendar = null;

					Console.WriteLine("Finding the calendar:" + argDic["t"]);

					#region process DetectOriginalType

					DetectOriginalType detectOriginalType = DetectOriginalType.none;

					if (argDic.ContainsKey("detectOriginal"))
					{
						Type t=typeof(DetectOriginalType);
						//&& argDic["detectOriginal"] == "killAllOld")
						FieldInfo[] fis = t.GetFields();
						foreach (FieldInfo fi in fis)
						{
							if (fi.Name == argDic["detectOriginal"])
							{
								detectOriginalType = (DetectOriginalType)fi.GetRawConstantValue();
								break;
							}
						}
					}


					#endregion

					#region check if there is already a calendar with the same name
					foreach (CalendarEntry entry in resultFeed.Entries)
					{
						if (entry.Title.Text == argDic["t"])
						{
							Console.WriteLine("Found " + argDic["t"]);

							targetCalendar = entry;

							#region kill all the old items

							if (detectOriginalType== DetectOriginalType.killAllOld)
							{
								Console.WriteLine("Killing originals");
								EventQuery eventQuery = new EventQuery();
								eventQuery.Uri = new Uri(targetCalendar.Links[0].AbsoluteUri);
								eventQuery.NumberToRetrieve = 1000;
								// Tell the service to query:
								EventFeed eventFeed = service.Query(eventQuery);

								foreach (EventEntry eventEntry in eventFeed.Entries)
								{
									Console.Write(".");
									eventEntry.Delete();
								}
								Console.WriteLine("finish");
							}
							#endregion

							break;

						}

					}
					#endregion

					if (targetCalendar == null)
					{
						#region create new calendar
						targetCalendar = new CalendarEntry();
						targetCalendar.Title.Text = argDic["t"];
						targetCalendar.Summary.Text = "此相簿由相簿資料轉出。";
						targetCalendar.TimeZone = "Asia/Taipei";
						targetCalendar.Hidden = false;
						targetCalendar.Color = "#2952A3";
						targetCalendar.Location = new Where("", "", "");

						Uri postUri = new Uri("http://www.google.com/calendar/feeds/default/owncalendars/full");
						targetCalendar = (CalendarEntry)service.Insert(postUri, targetCalendar);

						#endregion
					}

					#region process account
					{
						XmlDocument xd = new XmlDocument();

						xd.Load(argDic["s"]);
						foreach (XmlElement xeAlbum in xd.GetElementsByTagName("Album"))
						{
							if (xeAlbum.GetAttribute("summary").IndexOf("[Exclude From Picasa Summary Maker]") >= 0) continue;
							Console.WriteLine("Processing " + xeAlbum.GetAttribute("title"));

							XmlNodeList xnlPhoto = xeAlbum.GetElementsByTagName("Photo");

							Dictionary<DateTime, List<XmlElement>> dicPhoto = new Dictionary<DateTime, List<XmlElement>>();

							int total = xnlPhoto.Count;
							int current = 0;
							foreach (XmlElement xePhoto in xnlPhoto)
							{
								#region process each photo
								//dicPhoto.ContainsKey()
								string ds = xePhoto.GetAttribute("timestamp");
								if (ds == null) ds = xePhoto.GetAttribute("updated");
								if (ds == null) ds = xePhoto.GetAttribute("published");
								DateTime date = DateTime.Parse(ds);
								date = date.Date;

								List<XmlElement> list = null;

								if (dicPhoto.ContainsKey(date))
								{
									list = dicPhoto[date];
								}
								else
								{
									list = new List<XmlElement>();
									dicPhoto.Add(date, list);
								}
								xePhoto.SetAttribute("index", (current++).ToString());
								list.Add(xePhoto);
								#endregion
							}

							Dictionary<DateTime, List<XmlElement>>.Enumerator photoListEnum =
								dicPhoto.GetEnumerator();

							while (photoListEnum.MoveNext())
							{
								List<XmlElement> photoList = photoListEnum.Current.Value;

								#region process each list

								Console.WriteLine("Processing date " + photoListEnum.Current.Key.ToString());


								string albumFeedUri = targetCalendar.Links[0].AbsoluteUri;

								#region kill old
								if (detectOriginalType == DetectOriginalType.replaceOld)
								{
									Console.Write("Finding old ");
									EventQuery eqFindOld = new EventQuery(albumFeedUri);
									eqFindOld.StartTime = photoListEnum.Current.Key;
									eqFindOld.EndTime = photoListEnum.Current.Key.AddHours(1);
									EventFeed findOldFeed = service.Query(eqFindOld);
									foreach (EventEntry entry in findOldFeed.Entries)
									{
										if (entry.Title.Text == xeAlbum.GetAttribute("title"))
										{
											Console.Write("-");
											entry.Delete();
										}
										else
										{
											Console.Write(".");
										}
									}
								}
								#endregion

								#region insert new event

								#region web content link

								#region calculate the date-removed title
								string albumTitle = xeAlbum.GetAttribute("title");
								if (albumTitle[0] == '[')
								{
									int p = albumTitle.IndexOf(']');
									if (p >= 0)
									{
										albumTitle = albumTitle.Substring(p + 1);
									}
								}
								#endregion

								WebContentLink webContentLink = new WebContentLink();
								XmlElement fstElement = photoList[0];
								//object o=fstElement.GetElementsByTagName("Thumbnail");
								XmlElement xeThumbnail = (XmlElement)fstElement.GetElementsByTagName("Thumbnail")[0];

								webContentLink.Title = albumTitle;

								webContentLink.Type = "application/x-google-gadgets+xml";
								webContentLink.Url =
                                    "http://travel-suit.googlecode.com/svn/trunk/src/CalendarHelper/picasaGadget.xml"
									;

								webContentLink.Icon = Uri.EscapeUriString(xeThumbnail.GetAttribute("url"));

								string[] items = xeThumbnail.GetAttribute("size").Split(',');

								webContentLink.Width = Math.Max(300, uint.Parse(items[0]));
								webContentLink.Height = Math.Max(200, uint.Parse(items[1]) + 150);

								webContentLink.GadgetPreferences["albumTitle"] = GlobalObject.escape(albumTitle);
								webContentLink.GadgetPreferences["albumUrl"] = xeAlbum.GetAttribute("picasaUrl");

								webContentLink.GadgetPreferences["thumbUrl"] = xeThumbnail.GetAttribute("url");
								webContentLink.GadgetPreferences["feed"] = xeAlbum.GetAttribute("feedUri") + "&kind=photo&alt=rss";

								webContentLink.GadgetPreferences["index"] = fstElement.GetAttribute("index");


								#region set the summary album url
								string summaryAlbumUrl;
								if (argDic.TryGetValue("summaryAlbumUrl", out summaryAlbumUrl))
								{
									webContentLink.GadgetPreferences["summaryAlbumUrl"] = summaryAlbumUrl;
								}

								#endregion

								#endregion

								#region create event
								{
									EventEntry entry = new EventEntry();
									entry.WebContentLink = webContentLink;

									entry.Title.Text = xeAlbum.GetAttribute("title");

									DateTime t = photoListEnum.Current.Key;
									entry.Times.Add(new When(t, t.AddHours(1)));

									#region where
									Where eventLocation = new Where();
									eventLocation.ValueString = "taiwan";
									entry.Locations.Add(eventLocation);

									#endregion

									try
									{
									    EventEntry createdEntry = (EventEntry)service.Insert(new Uri(albumFeedUri), entry);
                                        Console.WriteLine(" +");
									}
									catch (Exception ex)
									{
                                        Console.WriteLine("[ERROR while create new calendar entry]");
										Console.WriteLine(ex.Message);
										Console.WriteLine(ex.StackTrace);
									}
								
								}
								#endregion


								#endregion

								#endregion
							}
						}

					} 
					#endregion

					#endregion
				}
				break;
			}
		}

		static CalendarService createCalendarService(string account, string pw)
		{
			Console.WriteLine("Try to login " + account);
			CalendarService myService = new CalendarService("calendarService");
			myService.setUserCredentials(account+"@gmail.com", pw);
			
			//GDataGAuthRequestFactory factory = (GDataGAuthRequestFactory)myService.RequestFactory;
			//factory.MethodOverride = true;
			//factory.Proxy = HttpWebRequest.DefaultWebProxy;
			

			Console.WriteLine("Login finished");
			return myService;
		}

		#region inner classes
		enum DetectOriginalType
		{
			none, killAllOld, replaceOld
		}
		#endregion
	}
}
